<?php


namespace Asf\Foundation\Http;

use Asf\Database\ConnectionResolver;
use Asf\Database\RedisPool;
use Asf\Http\Request;
use Asf\Http\Response;
use Asf\Routing\Router;
use Asf\Session\NativeSessionStorage;
use Asf\Session\RedisSessionHandler;
use DI\Container;
use function DI\get;
use FastRoute\DataGenerator;
use FastRoute\DataGenerator\GroupCountBased;
use FastRoute\RouteCollector;
use FastRoute\RouteParser;
use function DI\create;
use Illuminate\Database\Capsule\Manager;
use Illuminate\Database\Eloquent\Model;
use SessionHandlerInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\Loader\LoaderInterface;
use Asf\Contracts\Http\Response as ResponseInterface;

class Kernel implements \Asf\Contracts\Http\Kernel
{
    /**
     * @var Container
     */
    public static $container;

    //定义依赖和配置类
    public static function staticBootstrap()
    {
        self::initRouter();
        self::initSession();
        self::initRequest();
        self::initTemplateEngine();
    }

    /**
     * @param  Request $request
     * @return Response
     */
    public function handle($request)
    {
        //指定Session处理器
//        $request->setSession(self::$container->get(Session::class));
//
//
//        if ($request->cookies->has($request->getSession()->getName())) {
//            $sessId = $request->cookies->get($request->getSession()->getName());
//        } else {
//            $sessId = session_create_id();
//        }
//
//        session_id($sessId);
//        //启动session
//        $request->getSession()->start();


        self::$container->set(Request::class, $request);

        /** @var Router $router */
        $router = self::$container->get(Router::class);
        $route = $router->matchRoute($request);

        try {
            $response = $route->run();

        } catch (\Throwable $e) {
            echo $e->getMessage() . PHP_EOL;
            $response = new Response($e->getMessage(), 500);
        }

//        $request->getSession()->save();

        return $response;

    }

    public static function initRouter()
    {
        self::$container->set(RouteParser::class, create(RouteParser\Std::class));
        self::$container->set(DataGenerator::class, create(GroupCountBased::class));

        self::$container->set(\FastRoute\Dispatcher\GroupCountBased::class, function(RouteCollector $routeCollector) {
            return new \FastRoute\Dispatcher\GroupCountBased($routeCollector->getData());
        });
    }

    //定义模板变量的依赖
    public static function initTemplateEngine()
    {
        self::$container->set(LoaderInterface::class,
            create(FilesystemLoader::class)->constructor(self::$container->get('templatePath')));

        self::$container->set(Environment::class, function(LoaderInterface $loader) {
            return new Environment($loader, [
                'debug' => my_env('APP_ENV', 'PRO') == 'LOCAL' ? true : false,
                'cache' => my_env('APP_ENV', 'PRO') == 'LOCAL' ? false : self::$container->get('templateCachePath'),
            ]);
        });
    }

    //启用Http方法重写，使用请求中的 _method 重写Http方法
    public static function initRequest()
    {
        \Symfony\Component\HttpFoundation\Request::enableHttpMethodParameterOverride();
    }

    //定义session依赖
    public static function initSession()
    {
        self::$container->set(SessionHandlerInterface::class, create(\Asf\Session\RedisSessionHandler::class));
        self::$container->set(SessionStorageInterface::class,
            create(NativeSessionStorage::class)->constructor([], self::$container->get(SessionHandlerInterface::class), null));

        self::$container->set(Session::class, function(SessionStorageInterface $sessionStorage) {
            return new Session($sessionStorage);
        });
    }

    //定义数据库依赖
    public static function initDatabase()
    {
        self::$container->set(Manager::class, get(ConnectionResolver::class));

        Model::setConnectionResolver(self::$container->get(Manager::class));

        self::$container->set(RedisPool::class, function (){
            return new RedisPool();
        });
    }
}